查看原文
其他

如何通过 open-local 玩转容器本地存储? | 龙蜥技术

惠志、宇志、瑜佳 OpenAnolis龙蜥 2022-10-17

编者按:云原生背景下,本地存储相比分布式存储,在易用性、可维护性、IO 性能上都更胜一筹,但使用本地存储任然有诸多问题。那么 open-local 会带来什么不一样的体验呢?来看看作者怎么说。本文整理自龙蜥大讲堂第 30 期,精彩分享视频回放已上传至龙蜥官网(首页-动态-视频),欢迎查看!

云原生背景下,有状态应用需要借助一套存储方案进行数据持久化保存。本地存储相比分布式存储,在易用性、可维护性、IO 性能上都更胜一筹,但使用本地存储作为目前低成本交付 Kubernetes 集群,依然存在许多问题:
  • 本地存储管理能力有限:使用本地存储需要一定的人力成本,如通过为节点打标来限制 Pod 调度、人工管理不同机型的磁盘、人工通过 Hostpath 方式挂载指定磁盘到容器等;同时还有一些现场交付问题,如绑定了错误的宿主机路径使得故障无法及时发现,这些都严重影响了 K8s 交付效率以及应用运行时稳定性。

  • 本地存储空间隔离能力缺失:应用挂载不适当的宿主机目录(如挂载到宿主机根路径)导致宿主机故障,如因应用数据写满磁盘导致容器运行时无响应、触发 Pod 驱逐等问题。

  • K8s 原生本地存储能力有限。通过 Hostpath 无法做到节点保持,使得 Pod 漂移后应用数据丢失;而使用半自动静态 Local PV 可保证节点保持,但是无法实现全自动,仍然需要为人为参与(如创建文件夹路径,为节点打标等);无法使用一些高级存储能力(例如快照)。

针对以上问题, open-local 应用而生,接下来一起来看看 open-local 都有哪些性能?

open-local 介绍

开源地址:https://github.com/alibaba/open-local‍
open-local 是阿里巴巴开源的一款本地存储管理系统。通过 open-local,在 Kubernetes 上使用本地存储就像使用集中式存储一样简单。
目前 open-local 支持以下存储特性:本地存储池管理、存储卷动态分配、存储调度算法扩展、存储卷扩容、存储卷快照、存储卷监控、存储卷 IO 限流、原生块设备及临时卷。

1、use case

  • 应用本身已支持多副本高可用,希望使用本地盘以提高存储资源利用率,提高数据读写性能,如 HBase、MinIO 等。

  • 应用期望数据卷具备容量隔离能力,避免出现诸如日志打满系统盘的情况。

  • 应用需要大量本地存储并依赖节点保持,如 etcd、zookeeper、Elasticsearch 等。

  • 集群本地磁盘数量众多,希望通过调度器实现有状态应用的自动化部署。

  • 通过存储快照能力为数据库类应用备份瞬时数据等。

2、架构

┌─────────────────────────────────────────────────────────────────────────────┐│ Master ││ ┌───┬───┐ ┌────────────────┐ ││ │Pod│PVC│ │ API-Server │ ││ └───┴┬──┘ └────────────────┘ ││ │ bound ▲ ││ ▼ │ watch ││ ┌────┐ ┌───────┴────────┐ ││ │ PV │ │ Kube-Scheduler │ ││ └────┘ ┌─┴────────────────┴─┐ ││ ▲ │ open-local │ ││ │ │ scheduler-extender │ ││ │ ┌────►└────────────────────┘◄───┐ ││ ┌──────────────────┐ │ │ ▲ │ ││ │ NodeLocalStorage │ │create│ │ │ callback ││ │ InitConfig │ ┌┴──────┴─────┐ ┌──────┴───────┐ ┌────┴────────┐ ││ └──────────────────┘ │ External │ │ External │ │ External │ ││ ▲ │ Provisioner │ │ Resizer │ │ Snapshotter │ ││ │ watch ├─────────────┤ ├──────────────┤ ├─────────────┤ ││ ┌─────┴──────┐ ├─────────────┴──┴──────────────┴──┴─────────────┤GRPC││ │ open-local │ │ open-local │ ││ │ controller │ │ CSI ControllerServer │ ││ └─────┬──────┘ └────────────────────────────────────────────────┘ ││ │ create │└──────────┼──────────────────────────────────────────────────────────────────┘┌──────────┼──────────────────────────────────────────────────────────────────┐│ Worker │ ││ │ ││ ▼ ┌───────────┐ ││ ┌──────────────────┐ │ Kubelet │ ││ │ NodeLocalStorage │ └─────┬─────┘ ││ └──────────────────┘ │ GRPC Shared Disks ││ ▲ ▼ ┌───┐ ┌───┐ ││ │ ┌────────────────┐ │sdb│ │sdc│ ││ │ │ open-local │ create volume └───┘ └───┘ ││ │ │ CSI NodeServer ├───────────────► VolumeGroup ││ │ └────────────────┘ ││ │ ││ │ Exclusive Disks ││ │ ┌─────────────┐ ┌───┐ ││ │ update │ open-local │ init device │sdd│ ││ └────────────────┤ agent ├────────────────► └───┘ ││ └─────────────┘ Block Device ││ │└─────────────────────────────────────────────────────────────────────────────┘
2.1 open-local 包含四个组件:
1)scheduler-extender:作为 Kube-Scheduler 的扩展组件,通过 Extender 方式实现,新增本地存储调度算法。
2)CSI 插件:按照 CSI(Container Storage Interface) 标准实现本地磁盘管理能力,包含创建/删除/扩容存储卷、创建/删除快照、暴露存储卷 metrics 等能力。
3)agent:运行在集群中的每个节点,根据配置清单初始化存储设备,并通过上报集群中本地存储设备信息以供 Scheduler-Extender 决策调度。
4)controller:获取集群存储初始化配置,并向运行在各个节点的 Agent 下发详细的资源配置清单。
2.2 open-local 包含两个 CRD
1)NodeLocalStorage:open-local 通过 NodeLocalStorage 资源上报每个节点上的存储设备信息,该资源由 controller 创建,由每个节点的 agent 组件更新其 status。该 CRD 属于全局范围的资源。
2)NodeLocalStorageInitConfig:open-local controller 可通过 NodeLocalStorageInitConfig 资源创建每个 NodeLocalStorage 资源。NodeLocalStorageInitConfig 资源中包含全局默认节点配置和特定节点配置,若节点的 node label 满足表达式则使用特定节点配置,否则使用默认配置。

如何在 ack-distro 中使用 open-local

1、初始化配置

前置条件:环境中已经安装 lvm 工具
ack-distro 部署时会默认安装 open-local。
编辑 NodeLocalStorageInitConfig 资源,进行存储初始化配置。
# kubectl edit nlsc open-local
使用 open-local 要求环境中有 VG(VolumeGroup),若用户环境中已存在 VG 且有剩余空间,则可以配置在白名单;若环境中没有 VG,用户需提供一个块设备名称供 open-local 创建 VG。
apiVersion: csi.aliyun.com/v1alpha1kind: NodeLocalStorageInitConfigmetadata:name: open-localspec:globalConfig: # 全局默认节点配置,初始化创建 NodeLocalStorage 时会填充到其Spec中listConfig:vgs:include: # VolumeGroup 白名单,支持正则表达式- open-local-pool-[0-9]+- your-vg-name # 若环境中已有 VG,可以写入白名单由 open-local 纳管resourceToBeInited:vgs:- devices:- /dev/vdc # 若环境中没有 VG,用户需提供一个块设备name: open-local-pool-0 # 将块设备 /dev/vdc 初始化为名叫 open-local-pool-0 的 VG
NodeLocalStorageInitConfig 资源编辑完毕后,controller 和 agent 会更新所有节点的 NodeLocalStorage 资源。

2、存储卷动态供应

open-local 默认在集群中部署了一些存储类模板,我们以 open-local-lvm、open-local-lvm-xfs 和 open-local-lvm-io-throttling 举例:
# kubectl get scNAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGEopen-local-lvm local.csi.aliyun.com Delete WaitForFirstConsumer true 8dopen-local-lvm-xfs local.csi.aliyun.com Delete WaitForFirstConsumer true 6h56mopen-local-lvm-io-throttling local.csi.aliyun.com Delete WaitForFirstConsumer true
创建一个 Statefulset,该 Statefulset 使用 open-local-lvm 存储类模板。此时创建的存储卷文件系统为 ext4。若用户指定 open-local-lvm-xfs 存储模板,则存储卷文件系统为 xfs。
# kubectl apply -f https://raw.githubusercontent.com/alibaba/open-local/main/example/lvm/sts-nginx.yaml
检查 Pod/PVC/PV 状态,可看到存储卷创建成功:
# kubectl get podNAME READY STATUS RESTARTS AGEnginx-lvm-0 1/1 Running 0 3m5s# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEhtml-nginx-lvm-0 Bound local-52f1bab4-d39b-4cde-abad-6c5963b47761 5Gi RWO open-local-lvm 104s# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS AGElocal-52f1bab4-d39b-4cde-abad-6c5963b47761 5Gi RWO Delete Bound default/html-nginx-lvm-0 open-local-lvm 2m4skubectl describe pvc html-nginx-lvm-0

3、存储卷扩容

编辑对应 PVC 的 spec.resources.requests.storage 字段,将 PVC 声明的存储大小从 5Gi 扩容到 20 Gi。
# kubectl patch pvc html-nginx-lvm-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
检查 PVC/PV 状态:
# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEhtml-nginx-lvm-0 Bound local-52f1bab4-d39b-4cde-abad-6c5963b47761 20Gi RWO open-local-lvm 7h4m# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGElocal-52f1bab4-d39b-4cde-abad-6c5963b47761 20Gi RWO Delete Bound default/html-nginx-lvm-0 open-local-lvm 7h4m

4、存储卷快照

open-local 有如下快照类:
# kubectl get volumesnapshotclassNAME DRIVER DELETIONPOLICY AGEopen-local-lvm local.csi.aliyun.com Delete 20m
创建 VolumeSnapshot 资源:
# kubectl apply -f https://raw.githubusercontent.com/alibaba/open-local/main/example/lvm/snapshot.yamlvolumesnapshot.snapshot.storage.k8s.io/new-snapshot-test created# kubectl get volumesnapshotNAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGEnew-snapshot-test true html-nginx-lvm-0 1863 open-local-lvm snapcontent-815def28-8979-408e-86de-1e408033de65 19s 19s# kubectl get volumesnapshotcontentNAME READYTOUSE RESTORESIZE DELETIONPOLICY DRIVER VOLUMESNAPSHOTCLASS VOLUMESNAPSHOT AGEsnapcontent-815def28-8979-408e-86de-1e408033de65 true 1863 Delete local.csi.aliyun.com open-local-lvm new-snapshot-test 48s
创建一个新 Pod,该 Pod 对应的存储卷数据与之前快照点时刻的数据一致:
# kubectl apply -f https://raw.githubusercontent.com/alibaba/open-local/main/example/lvm/sts-nginx-snap.yamlservice/nginx-lvm-snap createdstatefulset.apps/nginx-lvm-snap created# kubectl get po -l app=nginx-lvm-snapNAME READY STATUS RESTARTS AGEnginx-lvm-snap-0 1/1 Running 0 46s# kubectl get pvc -l app=nginx-lvm-snapNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEhtml-nginx-lvm-snap-0 Bound local-1c69455d-c50b-422d-a5c0-2eb5c7d0d21b 4Gi RWO open-local-lvm 2m11s

5、原生块设备

open-local 支持创建的存储卷将以块设备形式挂载在容器中(本例中块设备在容器 /dev/sdd 路径):
# kubectl apply -f https://raw.githubusercontent.com/alibaba/open-local/main/example/lvm/sts-block.yaml
检查 Pod/PVC/PV 状态:
# kubectl get podNAME READY STATUS RESTARTS AGEnginx-lvm-block-0 1/1 Running 0 25s# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEhtml-nginx-lvm-block-0 Bound local-b048c19a-fe0b-455d-9f25-b23fdef03d8c 5Gi RWO open-local-lvm 36s# kubectl describe pvc html-nginx-lvm-block-0Name: html-nginx-lvm-block-0Namespace: defaultStorageClass: open-local-lvm...Access Modes: RWOVolumeMode: Block # 以块设备形式挂载入容器Mounted By: nginx-lvm-block-0...

6、IO 限流

open-local 支持为 PV 设置 IO 限流,支持 IO 限流的存储类模板如下:
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: open-local-lvm-io-throttlingprovisioner: local.csi.aliyun.comparameters: csi.storage.k8s.io/fstype: ext4 volumeType: "LVM" bps: "1048576" # 读写吞吐量限制在 1024KiB/s 上下 iops: "1024" # IOPS 限制在 1024 上下reclaimPolicy: DeletevolumeBindingMode: WaitForFirstConsumerallowVolumeExpansion: true
创建一个 Statefulset,该 Statefulset 使用 open-local-lvm-io-throttling 存储类模板。
# kubectl apply -f https://raw.githubusercontent.com/alibaba/open-local/main/example/lvm/sts-io-throttling.yaml
Pod 处于 Running 状态后,进入 Pod 容器中:
# kubectl exec -it test-io-throttling-0 sh
此时存储卷是以原生块设备挂载在 /dev/sdd 上,执行 fio 命令:
# fio -name=test -filename=/dev/sdd -ioengine=psync -direct=1 -iodepth=1 -thread -bs=16k -rw=readwrite -numjobs=32 -size=1G -runtime=60 -time_based -group_reporting
结果如下所示,可见读写吞吐量限制在 1024KiB/s 上下:
......
Run status group 0 (all jobs): READ: bw=1024KiB/s (1049kB/s), 1024KiB/s-1024KiB/s (1049kB/s-1049kB/s), io=60.4MiB (63.3MB), run=60406-60406msec WRITE: bw=993KiB/s (1017kB/s), 993KiB/s-993KiB/s (1017kB/s-1017kB/s), io=58.6MiB (61.4MB), run=60406-60406msec
Disk stats (read/write): dm-1: ios=3869/3749, merge=0/0, ticks=4848/17833, in_queue=22681, util=6.68%, aggrios=3112/3221, aggrmerge=774/631, aggrticks=3921/13598, aggrin_queue=17396, aggrutil=6.75% vdb: ios=3112/3221, merge=774/631, ticks=3921/13598, in_queue=17396, util=6.75%

7、临时卷

open-local 支持为 Pod 创建临时卷,其中临时卷生命周期与 Pod 一致,即 Pod 删除后临时卷也随之删除。此处可理解为 open-local 版本的 emptydir。
# kubectl apply -f ./example/lvm/ephemeral.yaml
结果如下:
# kubectl describe po file-serverName: file-serverNamespace: default......Containers: file-server: ...... Mounts: /srv from webroot (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-dns4c (ro)Volumes: webroot: # 此为 CSI 临时卷 Type: CSI (a Container Storage Interface (CSI) volume source) Driver: local.csi.aliyun.com FSType: ReadOnly: false VolumeAttributes: size=2Gi vgName=open-local-pool-0 default-token-dns4c: Type: Secret (a volume populated by a Secret) SecretName: default-token-dns4c Optional: false

8、监控大盘

open-local 自带了监控大盘,用户可通过 Grafana 查看集群本地存储信息,包含存储设备和存储卷信息。
总而言之,借助 open-local ,在运维方面可减少人力成本,提高集群运行时的稳定性;功能方面,将本地存储的优势最大化,使用户不仅能体验到本地盘的高性能,同时各种高级存储特性丰富了应用场景,让广大开发者体验云原生带来的红利,实现应用上云尤其是有状态应用云原生部署关键一步。

关于视频回放和课件获取 

【视频回放】:视频回访已上传至龙蜥官网(可阅读原文直达):https://openanolis.cn/video 查看。
【PPT课件获取】:关注微信公众号(OpenAnolis),回复“龙蜥课件” 即可获取。有任何疑问请随时咨询龙蜥助手—小龙(微信:openanolis_assis)
—— 完 ——
加入龙蜥社群

加入微信群:添加社区助理-龙蜥社区小龙(微信:openanolis_assis),备注【龙蜥】与你同在;加入钉钉群:扫描下方钉钉群二维码。欢迎开发者/用户加入龙蜥社区(OpenAnolis)交流,共同推进龙蜥社区的发展,一起打造一个活跃的、健康的开源操作系统生态!

关于龙蜥社区龙蜥社区(OpenAnolis)是由企业单位、事业单位、社会团体、个人等在共建、共治、共享的基础上组成的非营利性开源社区。龙蜥社区成立于 2020 年 9 月,旨在构建一个开放、平等、协作、创新的 Linux 上游发行版社区及创新平台。龙蜥社区成立的短期目标是开发龙蜥操作系统(Anolis OS)作为 CentOS 停服后的应对方案,构建一个兼容国际 Linux 主流厂商的社区发行版。中长期目标是探索打造一个面向未来的操作系统,建立统一的开源操作系统生态,孵化创新开源项目,繁荣开源生态。目前,Anolis OS 8.6 已发布,更多龙蜥自研特性,支持 X86_64 、RISC-V、Arm64、LoongArch 架构,完善适配 Intel、兆芯、鲲鹏、龙芯等芯片,并提供全栈国密支持。欢迎下载:https://openanolis.cn/download加入我们,一起打造面向未来的开源操作系统!https://openanolis.cn往期精彩推荐

1.千人互动,18 位业界大咖,2022 开放原子全球开源峰会龙蜥专区总结来了

2.龙蜥社区支持全国首个政府采购云平台——政采云顺利完成 CentOS 迁移

3.面向云时代的龙蜥操作系统 是 CentOS 替代的最佳选择4.龙蜥社区首推“分层分类”顶设 发展以云为终态的开源产业创新生态5.龙蜥社区第二届理事大会圆满召开!理事换届选举、4 位特约顾问加入


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存